## @package karboom.patterns
# Extended patterns
#
# Extensions of karboom.classes.Pattern
#

import cairo

from karboom.classes import Pattern
from karboom.utils import interpolate

## Solid pattern
#
# Fill with solid colour.
#
class Solid(Pattern):
    
    ## Colour, in a 4-tuple formatted (r, g, b, a)
    colour = (0.0, 0.0, 0.0, 0.0)
    
    def __render__(self):
        return cairo.SolidPattern(self.colour[0], self.colour[1], self.colour[2], self.colour[3])
    
    @staticmethod
    def __interpolate__(percent, start, end, accel):
        if end.__class__.__name__ == 'Solid':
            return Solid(colour=(
                                 interpolate(percent, start.colour[0], end.colour[0], accel),
                                 interpolate(percent, start.colour[1], end.colour[1], accel),
                                 interpolate(percent, start.colour[2], end.colour[2], accel),
                                 interpolate(percent, start.colour[3], end.colour[3], accel),
                                 )
                        )
            
        elif end.__class__.__name__ == 'LinearGradient':
            return LinearGradient(position=end.position,
                                  size=end.size,
                                  stops=dict([(k, 
                                               (
                                                interpolate(percent, start.colour[0], v[0], accel),
                                                interpolate(percent, start.colour[1], v[1], accel),
                                                interpolate(percent, start.colour[2], v[2], accel),
                                                interpolate(percent, start.colour[3], v[3], accel)
                                                )) for k, v in end.stops.iteritems()])
                                  )
            
        elif end.__class__.__name__ == 'RadialGradient':
            return LinearGradient(circles=end.size,
                                  stops=dict([(k, 
                                               (
                                                interpolate(percent, start.colour[0], v[0], accel),
                                                interpolate(percent, start.colour[1], v[1], accel),
                                                interpolate(percent, start.colour[2], v[2], accel),
                                                interpolate(percent, start.colour[3], v[3], accel)
                                                )) for k, v in end.stops.iteritems()])
                                  )
            
        else:
            return Pattern.__naiveinterpolate__(percent, start, end, accel)
        
## Gradient pattern
#
# Base class for gradients - should not be called directly.
#
class Gradient(Pattern):
    
    ## Colour stops, in a dictionary formatted {offset: (r, g, b, a)}
    stops = {}
    
## Linear gradient pattern
#
# Fill with a linear gradient.
#
class LinearGradient(Gradient):
    
    ## Position of gradient, in 2-tuple formatted (x, y)
    position = (0, 0)
    
    ## Size of gradient, in a 2-tuple formatted (width, height)
    gradsize = (0, 0)
    
    def __render__(self):
        lg = cairo.LinearGradient(self.position[0], self.position[1], self.gradsize[0], self.gradsize[1])
        for o, c in self.stops.iteritems():
            lg.add_color_stop_rgba(o, c[0], c[1], c[2], c[3])
        return lg
    
    @staticmethod
    def __interpolate__(percent, start, end, accel):
        if end.__class__.__name__ == 'Solid':
            return LinearGradient(position=end.position,
                                  size=end.size,
                                  stops=dict([(k, (
                                                   interpolate(percent, v[0], end.colour[0], accel),
                                                   interpolate(percent, v[1], end.colour[1], accel),
                                                   interpolate(percent, v[2], end.colour[2], accel),
                                                   interpolate(percent, v[3], end.colour[3], accel)
                                                   )) for k, v in start.stops.iteritems()])
                                 )
            
        elif end.__class__.__name__ == 'LinearGradient' and (len(start.stops) == len(end.stops) and filter(lambda x: x not in end.stops.keys(), start.stops.keys()) == [] and filter(lambda x: x not in start.stops.keys(), end.stops.keys()) == []):
            return LinearGradient(position=(
                                            interpolate(percent, start.position[0], end.position[0], accel),
                                            interpolate(percent, start.position[1], end.position[1], accel)
                                            ),
                                  size=(
                                        interpolate(percent, start.size[0], end.size[0], accel),
                                        interpolate(percent, start.size[1], end.size[1], accel)
                                        ),
                                        
                                  stops=dict([(k, (
                                                   interpolate(percent, v[0], end.stops[k][0], accel),
                                                   interpolate(percent, v[1], end.stops[k][1], accel),
                                                   interpolate(percent, v[2], end.stops[k][2], accel),
                                                   interpolate(percent, v[3], end.stops[k][3], accel)
                                                   )) for k, v in start.stops.iteritems()])
                                  )
            
        else:
            return Pattern.__naiveinterpolate__(percent, start, end, accel)

## Radial gradient pattern
#
# Fill with a radial gradient.
class RadialGradient(Gradient):
    
    ## Circles, in a 2-3-tuple formatted ((x, y, radius), (x, y, radius))
    circles = ((0.0, 0.0, 0.0), (0.0, 0.0, 0.0))
    
    def __render__(self):
        rg = cairo.RadialGradient(self.circles[0][0], self.circles[0][1], self.circles[0][2], self.circles[1][0], self.circles[1][1], self.circles[1][2])
        for o, c in self.stops.iteritems():
            rg.add_color_stop_rgba(o, c[0], c[1], c[2], c[3])
        return rg